<?php

/**
 * @author Samuel Nogueira <snogueira@rocket-internet.pt>
 */
class AutoLoader {
	
	/**
	 * Class autoloader.
	 * Only handles classes in \app, \qore and \qore_base namespaces
	 * @param string $className class name
	 * @return boolean whether the class has been loaded successfully
	 * @throws Exception if namespace is not in lowercase or if file does not exist
	 */
	public static function autoload($fullClassName) {
		$pathParts = explode("\\", $fullClassName);
		$rootNamespace = array_shift($pathParts);
		$className = array_pop($pathParts);
		
		// if root namespace is not one of these, we do nothing
		if (!in_array($rootNamespace, array('app', 'qore', 'qore_base'))) return false;
		
		// see if any of the path components are not in lowercase
		foreach ($pathParts as $folder) {
			if ($folder != strtolower($folder)) {
				throw new Exception(Qore::t('qore', 'Namespace path in class "%s" must be in lowercase.', array($fullClassName)));
			}
		}
		
		// fetch base paths (in order of priority) for this root namespace
		$basePaths = array();
		$D = DIRECTORY_SEPARATOR;
		switch ($rootNamespace) {
			// '\app' namespace
			case 'app': $basePaths = array(
				QORE_APP_BASE_PATH
			); break;
			
			// '\qore' namespace
			case 'qore': $basePaths = array(
				QORE_APP_BASE_PATH.'ext'.$D,
				dirname(__FILE__).$D.'ext'.$D,
			); break;
			
			// '\qore_base' namespace
			case 'qore_base': $basePaths = array(
				dirname(__FILE__).$D,
			); break;
		}
		
		// test basepaths until an existing file is found
		$fullFile = null;
		$fileName = implode(DIRECTORY_SEPARATOR, $pathParts).DIRECTORY_SEPARATOR."{$className}.php";
		foreach ($basePaths as $basePath) {
			$fullFileCandidate = $basePath.$fileName;
			if (is_file($fullFileCandidate)) {
				$fullFile = $fullFileCandidate;
				break;
			}
		}
		
		// check if file exists
		if (!$fullFile) {
			return false;
		}
		
		// load file and check if class definition matches
		require_once($fullFile);
		if (!class_exists($fullClassName, false)) {
			return false;
		}
		
		return true;
	}

}
